package com.ruoyi.back.service.impl

import cn.hutool.core.bean.BeanUtil
import cn.hutool.core.date.DateUtil
import cn.hutool.core.util.RandomUtil
import cn.hutool.core.util.StrUtil
import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
import com.baomidou.mybatisplus.extension.plugins.pagination.Page
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
import com.baomidou.shaun.core.context.ProfileHolder
import com.ruoyi.app.common.*
import com.ruoyi.back.domain.UserMember
import com.ruoyi.back.domain.UserMemberOrder
import com.ruoyi.back.domain.dto.UserMemberOrderDto
import com.ruoyi.back.domain.dto.UserMemberOrderSearchDto
import com.ruoyi.back.domain.vo.PayRecordVo
import com.ruoyi.back.domain.vo.UserDetailVo
import com.ruoyi.back.domain.vo.UserMemberOrderDetailVo
import com.ruoyi.back.domain.vo.UserMemberOrderListVo
import com.ruoyi.back.enums.NoticeTypeEnum
import com.ruoyi.back.enums.PayStatusEnum
import com.ruoyi.back.enums.PayTypeEnum
import com.ruoyi.back.enums.UserTypeEnum
import com.ruoyi.back.mapper.UserMemberOrderMapper
import com.ruoyi.back.service.*
import com.ruoyi.common.core.page.PageDomain
import com.ruoyi.common.core.page.TableSupport
import com.ruoyi.socket.WebSocketServer
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.util.*

@Service
class UserMemberOrderServiceImpl : ServiceImpl<UserMemberOrderMapper, UserMemberOrder>(), UserMemberOrderService {

    @Autowired
    private lateinit var memberService: MemberService

    @Autowired
    private lateinit var appUserService: AppUserService

    @Autowired
    private lateinit var userMemberService: UserMemberService

    @Autowired
    private lateinit var userService: AppUserService

    @Autowired
    private lateinit var userMemberMessageService: UserMemberMessageService

    override fun createUserMemberOrder(userMemberOrderDto: UserMemberOrderDto): UserMemberOrder =
        UserMemberOrder().apply {
            BeanUtil.copyProperties(userMemberOrderDto, this)
            orderNum = "${DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss")}${RandomUtil.randomNumbers(8)}"
            userService.getById(ProfileHolder.getProfile().id)?.let { appUser ->
                userId = appUser.userId
                username = appUser.username
                createBy = appUser.id
            }
            payAmount = userMemberOrderDto.payAmount ?: memberService.getById(userMemberOrderDto.memberId)?.price ?: 0.0
        }.also { save(it) }


    override fun appUserDetail(userId: Long): Data<UserDetailVo> =
        userService.getById(userId)?.let { appUser ->
            Ok("获取用户详情信息成功", UserDetailVo().apply {
                userInfo = appUserService.appUserInfo(appUser.id!!)
                payRecords = payRecordList(appUser.id!!, TableSupport.buildPageRequest())
            })
        } ?: Fail(201, "当前用户不存在!")

    override fun payRecordList(userId: Long, pageDomain: PageDomain): Page<PayRecordVo> =
        page(
            Page(pageDomain.pageNum.toLong(), pageDomain.pageSize.toLong()), KtQueryWrapper(UserMemberOrder::class.java)
                .eq(UserMemberOrder::createBy, userId)
                .eq(UserMemberOrder::payStatus, PayStatusEnum.PAY_SUCCESS.code)
                .orderByDesc(UserMemberOrder::payDate)
        )
            .let { page: Page<UserMemberOrder> ->

                Page<PayRecordVo>().apply {
                    BeanUtil.copyProperties(page, this)
                    records = page.records.takeIf { it.isNotEmpty() }
                        ?.run {
                            map {
                                PayRecordVo().apply {
                                    BeanUtil.copyProperties(it, this)
                                    memberName = memberService.getNameByMemberId(it.memberId!!)
                                }
                            }
                        }
                }
            }

    override fun getUserMemberOrderByOrderNum(orderNum: String): UserMemberOrder? =
        getOne(KtQueryWrapper(UserMemberOrder::class.java).eq(UserMemberOrder::orderNum, orderNum))

    override fun userMemberOrderPage(userMemberOrderSearchDto: UserMemberOrderSearchDto): Page<UserMemberOrderListVo> =
        TableSupport.buildPageRequest().let { pageDomain ->

            page(
                Page(pageDomain.pageNum.toLong(), pageDomain.pageSize.toLong()),
                KtQueryWrapper(UserMemberOrder::class.java).apply {
                    eq(UserMemberOrder::payStatus, PayStatusEnum.PAY_SUCCESS.code)
                    if (StrUtil.isNotBlank(userMemberOrderSearchDto.searchParam)) {
//                        this.eq(UserMemberOrder::payStatus, PayStatusEnum.PAY_SUCCESS.code)
//                            .eq(UserMemberOrder::orderNum, userMemberOrderSearchDto.searchParam)
//                            .or().eq(UserMemberOrder::userId, userMemberOrderSearchDto.searchParam).or()
//                            .eq(UserMemberOrder::username, userMemberOrderSearchDto.searchParam)
                        eq(UserMemberOrder::userId, userMemberOrderSearchDto.searchParam)
                    }
                    gt(
                        StrUtil.isNotBlank(userMemberOrderSearchDto.payDateBeginDate),
                        UserMemberOrder::payDate,
                        userMemberOrderSearchDto.payDateBeginDate.date()
                    )
                    lt(
                        StrUtil.isNotBlank(userMemberOrderSearchDto.payDateEndDate),
                        UserMemberOrder::payDate,
                        userMemberOrderSearchDto.payDateEndDate.date()
                    )
                    userMemberOrderSearchDto.expire?.let { expire ->
                        eq(UserMemberOrder::expire, expire)
                    }
                    userMemberOrderSearchDto.channel?.let { channel ->
                        eq(UserMemberOrder::channel, channel)
                    }
                    orderByDesc(UserMemberOrder::payDate)
                }).let { page: Page<UserMemberOrder> ->

                Page<UserMemberOrderListVo>().apply {
                    BeanUtil.copyProperties(page, this)
                    records = page.records.takeIf { it.isNotEmpty() }?.run {
                        map {
                            UserMemberOrderListVo().apply {
                                BeanUtil.copyProperties(it, this)
                                payType = it.payType?.payType()
                                expire = when {
                                    DateUtil.compare(it.expireDate, Date()) < 0 -> "已到期"
                                    DateUtil.compare(it.expireDate, Date()) > 0 -> "未到期"
                                    else -> "未知"
                                }
                                payDate = it.createTime?.format()
                                expireDate = it.expireDate?.format()
                                validityPeriod = memberService.getById(it.memberId)
                                    ?.run { if (period != 0) "${period}${periodUnit?.unitType()}" else "永久" }
                            }
                        }
                    }
                }
            }
        }

    override fun userMemberOrderDetail(orderId: Long): Data<UserMemberOrderDetailVo> =
        getById(orderId)?.let { order ->
            Ok("获取订单详情成功", UserMemberOrderDetailVo().apply {
                userInfo = appUserService.appUserInfo(order.createBy!!)
                BeanUtil.copyProperties(order, this)
                payType = order.payType?.payType()
                expire = when (order.expire) {
                    true -> "已到期"
                    false -> "未到期"
                    null -> "未知"
                }
                payDate = order.payDate?.format()
                expireDate = order.expireDate?.format()
                validityPeriod = memberService.getById(order.memberId)?.run { "${period}${periodUnit?.unitType()}" }
            })
        } ?: Fail(201, "不存在当前订单")

    override fun removeMemberOrder(orderId: Long): Data<Boolean> =
        getById(orderId)?.run {
            Ok("移除成功", removeById(orderId))
        } ?: Fail(201, "不存在当前资源")

    override fun updateMemberPayStatus(orderNum: String, payTypeEnum: PayTypeEnum) {
        getOne(
            KtQueryWrapper(UserMemberOrder::class.java)
                .eq(UserMemberOrder::orderNum, orderNum)
                .eq(UserMemberOrder::payType, payTypeEnum.code)
        )
            ?.let {

                memberService.getById(it.memberId).takeIf { it.name == "视频单次收费" || it.name == "图片单次收费" }
                    ?.run {
                        updateById(it.apply {
                            payDate = DateUtil.date()
                            memberType = memberService.getById(it.memberId)?.name
                            payStatus = PayStatusEnum.PAY_SUCCESS.code
                        })
                    } ?: run {
                    //发送会员开通消息
                    userMemberMessageService.sendUserMessage(NoticeTypeEnum.OPEN_USER_MEMBER, it.createBy!!)
                    WebSocketServer.sendMessage(it.createBy)

                    userMemberService.getUserMemberByUserId(it.createBy!!)
                        ?.run {
                            //发送会员续费消息
                            userMemberMessageService.sendUserMessage(NoticeTypeEnum.RENEW_MEMBER, it.createBy!!)
                            WebSocketServer.sendMessage(it.createBy)
                            userMemberService.updateById(this.apply {
                                val (begin, end) = userMemberService.computeMemberDate(
                                    this,
                                    memberService.memberDay(it.memberId!!) ?: 0
                                )
                                beginMemberDate = begin
                                endMemberDate = end

                                appUserService.updateById(appUserService.getById(it.createBy)?.run {
                                    apply {
                                        userType = UserTypeEnum.MEMBER.code
                                        totalChangeFaceCount = totalChangeFaceCount?.plus(memberService.getById(it.memberId)?.receiveCount ?: 0)
                                    }
                                })
                                updateById(it.apply {
                                    expireDate = endMemberDate
                                    payDate = DateUtil.date()
                                    memberType = memberService.getById(it.memberId)?.name
                                    payStatus = PayStatusEnum.PAY_SUCCESS.code
                                })
                            })
                        }
                        ?: kotlin.run {
                            userMemberService.save(UserMember().apply {
                                createBy = it.createBy
                                beginMemberDate = DateUtil.date()
                                endMemberDate =
                                    DateUtil.offsetDay(beginMemberDate, memberService.memberDay(it.memberId!!) ?: 0)
                                appUserService.updateById(appUserService.getById(it.createBy)?.run {
                                    apply {
                                        userType = UserTypeEnum.MEMBER.code
                                        totalChangeFaceCount = totalChangeFaceCount?.plus(memberService.getById(it.memberId)?.receiveCount ?: 0)
                                    }
                                })
                                updateById(it.apply {
                                    expireDate = endMemberDate
                                    payDate = DateUtil.date()
                                    payStatus = PayStatusEnum.PAY_SUCCESS.code
                                })
                            })
                        }
                }

            }
    }

    override fun getUserLastOrderName(userId: Long): String? =
        getOne(
            KtQueryWrapper(UserMemberOrder::class.java)
                .eq(UserMemberOrder::createBy, userId)
                .eq(UserMemberOrder::payStatus, PayStatusEnum.PAY_SUCCESS.code)
                .orderByDesc(UserMemberOrder::payDate)
                .last("limit 1")
        )
            ?.run {
                memberService.getById(memberId)?.name
            }
}